#include <iostream>
using namespace std;

#include "tlistacom.h"

//! \file tlistacom.cpp
//! \brief Implementacion de la clase TListaCom, TListaNodo y TListaPos

TListaNodo::TListaNodo():anterior(NULL), siguiente(NULL){}

TListaNodo::TListaNodo(const TListaNodo &n):e(n.e), anterior(n.anterior), siguiente(n.siguiente){}

TListaNodo::~TListaNodo()
{
	siguiente=anterior=NULL;
	e = 0;
}

TListaNodo&
TListaNodo::operator= (const TListaNodo &n)
{
	if (this != &n)
	{
		e = n.e;
		anterior = n.anterior;
		siguiente = n.siguiente;
	}
	return *this;
}

//======================================================================

TListaPos::TListaPos(const TListaPos& p)
{
	if (p.pos != NULL)
	{
		pos = p.pos;
	}
}

TListaPos::~TListaPos()
{
	pos = NULL;
}

TListaPos &
TListaPos::operator=(const TListaPos & p)
{
	if (this != &p)
	{
		pos = p.pos;
	}
	return *this;
}

bool 
TListaPos::operator==(const TListaPos & p) const
{
	return (p.pos->e == pos->e);
}

bool 
TListaPos::operator!=(const TListaPos & p) const
{
	return !(p.pos->e == pos->e);
}

TListaPos
TListaPos::Anterior() const
{
	TListaPos ret;
	ret.pos = NULL;
	if (pos != NULL && pos->anterior!= NULL)
	{
		ret.pos = pos->anterior;
	}
	return ret;
}

TListaPos
TListaPos::Siguiente() const
{
	TListaPos ret;
	ret.pos = NULL;
	if (pos != NULL && pos->siguiente!= NULL)
	{
		ret.pos = pos->siguiente;
	}
	return ret;
}

//======================================================================

TListaCom::TListaCom(const TListaCom &l)
{
	TListaPos e, f;
	
	if (!l.EsVacia())
	{
		e.pos = l.primero;
		primero = new TListaNodo(*e.pos);
		f.pos = primero;
		for (e.pos = e.pos->siguiente; e.pos != NULL; e.pos = e.pos->siguiente)
		{
			f.pos->siguiente = new TListaNodo(*e.pos);
			f.pos->siguiente->anterior = f.pos;
			f.pos = f.pos->siguiente;
		}	
		ultimo = f.pos;
		e.pos = NULL;
		f.pos = NULL;
	}
}

TListaCom::~TListaCom()
{
	TListaPos e;
	
	while (primero != NULL)
	{
		e.pos = primero;
		primero = primero->siguiente;
		delete e.pos;
		e.pos = NULL;
	}
	ultimo = NULL;
}

TListaCom& 
TListaCom::operator=(const TListaCom & l)
{
	TListaPos e, f;
	if (this != &l)
	{
		if (!this->EsVacia())
		{
			while (primero != NULL)
			{
				e.pos = primero;
				primero = primero->siguiente;
				delete e.pos;
				e.pos = NULL;
			}
			ultimo = NULL;	
		}
			if (!l.EsVacia())
			{
				e.pos = l.primero;
				primero = new TListaNodo(*e.pos);
				f.pos = primero;
				for (e.pos = e.pos->siguiente; e.pos != NULL; e.pos = e.pos->siguiente)
				{
					f.pos->siguiente = new TListaNodo(*e.pos);
					f.pos->siguiente->anterior = f.pos;
					f.pos = f.pos->siguiente;
				}	
				ultimo = f.pos;
				e.pos = NULL;
				f.pos = NULL;
			}
	}
	return *this;
}
	
bool 
TListaCom::operator==(const TListaCom &l) const
{
	TListaPos e,f;
	bool ret = true;
	
	if (l.primero != NULL && primero != NULL)
	{
		for (e.pos = l.primero, f.pos = primero; e.pos != l.ultimo && f.pos != ultimo;
			e.pos = e.pos->siguiente, f.pos = f.pos->siguiente)
			{
				if (!(e.pos->e == f.pos->e))
				{
					ret = false;
				}
			}
			if (ultimo->e != l.ultimo->e)
			{
				ret = false;
			}
	}
	else
	{
		if (l.primero != primero)
			ret = false;
	}
	return ret;
}

bool
TListaCom::operator!=(const TListaCom &l) const
{
	return !operator==(l);
}

TListaCom
TListaCom::operator+(const TListaCom &l) const
{
	TListaCom ret(*this);
	TListaPos e;
	
	if (!l.EsVacia())
	{
		for (e.pos = l.primero; e.pos != NULL; e.pos = e.pos->siguiente)
		{
			ret.ultimo->siguiente = new TListaNodo(*e.pos);
			ret.ultimo->siguiente->anterior = ret.ultimo;
			ret.ultimo = ret.ultimo->siguiente;
		}
	}
	return ret;
}

TListaCom
TListaCom::operator-(const TListaCom &l) const
{
	TListaPos e, f;
	TListaNodo aux;
	TListaCom ret;
	f.pos = NULL;
	
	if (!l.EsVacia())
	{
		for (e.pos = primero; e.pos != NULL; e.pos = e.pos->siguiente)
		{
			if (!l.Buscar(e.pos->e))
			{
				aux.e = e.pos->e;
				if (ret.primero == NULL)
				{
					ret.primero = new TListaNodo(aux);
					ret.primero->siguiente = NULL;
					ret.primero->anterior = NULL;
					f.pos = ret.primero;
				}
				else
				{
					f.pos->siguiente = new TListaNodo(aux);
					f.pos->siguiente->anterior = f.pos;
					f.pos = f.pos->siguiente;
				}
			}
		}
		ret.ultimo = f.pos;
	}
	else
	{
		ret = (*this);
	}
	
	return ret;
}

bool
TListaCom::EsVacia() const
{
	return (primero == NULL);
}		
		
bool
TListaCom::InsCabeza(const TComplejo &e)
{
	TListaNodo nodo;
	bool ret;
	
	nodo.e = e;
	if (primero == NULL)
	{
		ultimo = primero = new TListaNodo(nodo);
	}
	else
	{
		primero->anterior = new TListaNodo(nodo);
		primero->anterior->siguiente = primero;
		primero = primero->anterior;
	}
	if (primero != NULL)
	{
		ret = true;
	}
	return ret;
}
		

bool
TListaCom::InsCola(const TComplejo &e)
{
	TListaNodo nodo;
	bool ret;
	
	nodo.e = e;
	if (primero == NULL)
	{
		ultimo = primero = new TListaNodo(nodo);
	}
	else
	{
		ultimo->siguiente = new TListaNodo(nodo);
		ultimo->siguiente->anterior = ultimo;
		ultimo = ultimo->siguiente;
	}
	if (ultimo != NULL)
	{
		ret = true;
	}
	return ret;
}		
		
bool 
TListaCom::InsertarI(const TComplejo & c, const  TListaPos & e)
{
	bool ret = false;
	TListaNodo aux;
	aux.e = c;
	if (!EsVacia() && e.pos != NULL && PerteneceALista(e))
	{
		if (e.pos->anterior == NULL)
		{
			e.pos->anterior = new TListaNodo(aux);
			if (e.pos->anterior != NULL)
			{
				ret = true;
				e.pos->anterior->siguiente = e.pos;
			}
			primero = e.pos->anterior;
		}
		else
		{
			TListaPos aux2;
			aux2.pos = e.pos->anterior;
			e.pos->anterior = new TListaNodo(aux);
			if (e.pos->anterior != NULL)
			{
				ret = true;
				e.pos->anterior->siguiente = e.pos;
				e.pos->anterior->anterior = aux2.pos;
				aux2.pos->siguiente = e.pos->anterior;
			}
			aux2.pos = NULL;
		}
	}
	return ret;
}

bool 
TListaCom::InsertarD(const TComplejo & c,const TListaPos & e)
{
	bool ret = false;
	TListaNodo aux;
	aux.e = c;
	if (!EsVacia() && e.pos != NULL && PerteneceALista(e))
	{
		if (e.pos->siguiente == NULL)
		{
			e.pos->siguiente = new TListaNodo(aux);
			if (e.pos->siguiente != NULL)
			{
				ret = true;
				e.pos->siguiente->anterior = e.pos;
				e.pos->siguiente->siguiente = NULL;
			}
			ultimo = e.pos->siguiente;
		}
		else
		{
			TListaPos aux2;
			aux2.pos = e.pos->siguiente;
			e.pos->siguiente = new TListaNodo(aux);
			if (e.pos->siguiente != NULL)
			{
				ret = true;
				e.pos->siguiente->anterior = e.pos;
				e.pos->siguiente->siguiente = aux2.pos;
				aux2.pos->anterior = e.pos->siguiente;
			}
			aux2.pos = NULL;
		}
	}
	return ret;
}

bool 
TListaCom::Borrar(const TComplejo &c)
{
	bool ret = false;
	TListaPos e;
	e.pos = primero;
	while(!ret && e.pos != NULL)
	{
		if (e.pos->e == c)
		{
			ret = true;
			if (e.pos->anterior == NULL)
			{
				primero = primero->siguiente;
				primero->anterior = NULL;
			}
			else if (e.pos->siguiente == NULL)
			{
				ultimo = ultimo->anterior;
				ultimo->siguiente = NULL;
			}
			else
			{
				e.pos->anterior->siguiente = e.pos->siguiente;
				e.pos->siguiente->anterior = e.pos->anterior;
			}
			e.pos->anterior = NULL;
			e.pos->siguiente = NULL;
			delete e.pos;
		}
		else
		{
			e.pos = e.pos->siguiente;
		}
	}
	e.pos = NULL;
	return ret;
}

bool
TListaCom::Borrar(const TListaPos &e)
{
	bool ret = false;
	
	if (PerteneceALista(e))
	{
		ret = true;
		if (e.pos->anterior == NULL)
		{
			primero = primero->siguiente;
			if (primero != NULL)
			{
				primero->anterior = NULL;
			}
		}
		else if (e.pos->siguiente == NULL)
		{
			ultimo = ultimo->anterior;
			if (ultimo != NULL)
			{
				ultimo->siguiente = NULL;
			}
		}
		else
		{
			e.pos->anterior->siguiente = e.pos->siguiente;
			e.pos->siguiente->anterior = e.pos->anterior;
		}
		e.pos->anterior = NULL;
		e.pos->siguiente = NULL;
		delete e.pos;
	}
	return ret;
}

bool 
TListaCom::BorrarTodos(const TComplejo &c)
{
	bool ret = false;
	TListaPos e, aux;
	e.pos = primero;
	
	while(e.pos != NULL)
	{
		if (e.pos->e == c)
		{
			aux.pos = e.pos;
			e.pos = e.pos->siguiente;
			ret = true;
			if (aux.pos->anterior == NULL)
			{
				primero = primero->siguiente;
				primero->anterior = NULL;
			}
			else if (aux.pos->siguiente == NULL)
			{
				ultimo = ultimo->anterior;
				ultimo->siguiente = NULL;
			}
			else
			{
				aux.pos->anterior->siguiente = aux.pos->siguiente;
				aux.pos->siguiente->anterior = aux.pos->anterior;
			}
			aux.pos->anterior = NULL;
			aux.pos->siguiente = NULL;
			delete aux.pos;
			aux.pos = NULL;
		}
		else
		{
			e.pos = e.pos->siguiente;
		}
	}
	e.pos = NULL;
	aux.pos = NULL;
	return ret;
}

TComplejo
TListaCom::Obtener(const TListaPos &p) const
{
	TComplejo ret;
	if (p.pos != NULL && PerteneceALista(p))
	{
		ret = p.pos->e;
	}
	return ret;
}
		
bool
TListaCom::Buscar(const TComplejo &c) const
{
	bool ret = false;
	TListaPos e;
	e.pos = primero;
	while(!ret && e.pos != NULL)
	{
		if (e.pos->e == c)
		{
			ret = true;
		}
		else
		{
			e.pos = e.pos->siguiente;
		}
	}
	e.pos = NULL;
	return ret;
}		
		
int
TListaCom::Longitud() const
{
	TListaPos e;
	int ret = 0;
	e.pos = primero;
	while (e.pos != NULL)
	{
		ret++;
		e.pos = e.pos->siguiente;
	}
	return ret;
}

TListaPos 
TListaCom::Primera() const
{
	TListaPos ret;
	ret.pos = primero;
	return ret;
}

TListaPos
TListaCom::Ultima() const
{
	TListaPos ret;
	ret.pos = ultimo;
	return ret;
}

ostream&
operator<<(ostream & os, const TListaCom &l)
{
	TListaPos e;
	bool espacio = false;
	os <<'{';
	if (l.primero != NULL)
	{
		for (e.pos = l.primero; e.pos != NULL; e.pos = e.pos->siguiente)
		{
			if (espacio)
			{
				os <<' ';
			}
			os << e.pos->e;
			espacio = true;
		}		
	}
	os <<'}';
	return os;
}

bool
TListaCom::PerteneceALista(const TListaPos &p) const
{
	TListaPos aux;
	aux.pos = primero;
	bool ret = false;
	if (p.pos != NULL)
	{
		while (!ret && aux.pos != NULL)
		{
			if (aux.pos == p.pos)
			{
				ret = true;
			}
			aux.pos = aux.pos->siguiente;
		}
	}
	return ret;
}
